﻿using System;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Hosting;
using System.Web.Caching;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Caramel.Web.Hosting
{
	public class AssemblyResourceVirtualPathProvider : VirtualPathProvider
	{
		public AssemblyResourceVirtualPathProvider()
			: this(AppDomain.CurrentDomain.GetAssemblies())
		{
		}

		public AssemblyResourceVirtualPathProvider(string pattern)
			: this(AppDomain.CurrentDomain.GetAssemblies(), pattern)
		{
		}

		public AssemblyResourceVirtualPathProvider(IEnumerable<Assembly> assemblies)
			: this(assemblies, null)
		{
		}

		public AssemblyResourceVirtualPathProvider(IEnumerable<Assembly> assemblies, string pattern)
		{
			this.AssemblyResources =
				assemblies.
					SelectMany(
						a =>
						a.
							GetManifestResourceNames().
							Select(
								n =>
								new AssemblyResource()
								{
									Name = n,
									AssemblyFullName = a.FullName
								}
							)
					);

			this.Pattern = pattern;
		}

		protected IEnumerable<AssemblyResource> AssemblyResources { get; private set; }

		protected string Pattern { get; set; }

		protected virtual bool IsAssemblyResource(string virtualPath)
		{
			var relativePath =
				VirtualPathUtility.
					ToAppRelative(virtualPath).
					Replace("~", "").
					Replace("/", ".");

			return
				this.
					AssemblyResources.
					Any(
						a =>
						{
							var result = new Regex(this.Pattern).IsMatch(a.Name);

							if (result)
							{
								int i = 0;
								i++;
							}

							return result;

							//if (this.Pattern != null)
							//{
							//    var index = a.Name.IndexOf(this.Pattern);

							//    if (index > 0)
							//    {
							//        var name = a.Name.Substring(index, a.Name.Length - index);

							//        if (relativePath.ToLowerInvariant().EndsWith(name.ToLowerInvariant()))
							//        {
							//            return true;
							//        }
							//    }
							//}

							//return false;
						}
					);
		}

		public override bool FileExists(string virtualPath)
		{
			return
				this.IsAssemblyResource(virtualPath) ||
				this.Previous.FileExists(virtualPath);
		}

		public override VirtualFile GetFile(string virtualPath)
		{
			if (this.Previous.FileExists(virtualPath))
			{
				return this.Previous.GetFile(virtualPath);
			}

			if (this.IsAssemblyResource(virtualPath))
			{
				var relativePath =
					VirtualPathUtility.
						ToAppRelative(virtualPath).
						Replace("~", "").
						Replace("/", ".");

				var assemblyResource =
					this.
						AssemblyResources.
						First(
							a =>
							{
								if (this.Pattern != null)
								{
									var result = new Regex(this.Pattern).IsMatch(a.Name);

									return result;

									//if (this.Pattern != null)
									//{
									//    var index = a.Name.IndexOf(this.Pattern);

									//    if (index > 0)
									//    {
									//        var name = a.Name.Substring(index, a.Name.Length - index);

									//        if (relativePath.ToLowerInvariant().EndsWith(name.ToLowerInvariant()))
									//        {
									//            return true;
									//        }
									//    }
									//}

									//return false;
								}

								return false;
							}
						);

				return
					new AssemblyResourceFile(
						assemblyResource.AssemblyFullName,
						assemblyResource.Name,
						virtualPath
					);
			}

			return this.Previous.GetFile(virtualPath);
		}

		public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
		{
			return 
				this.IsAssemblyResource(virtualPath) ? 
				null : 
				this.Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
		}
	}
}
